home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Parser / tokenizer.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-10  |  16.3 KB  |  820 lines

  1. /* Tokenizer implementation */
  2.  
  3. #include "pgenheaders.h"
  4.  
  5. #include <ctype.h>
  6.  
  7. #include "tokenizer.h"
  8. #include "errcode.h"
  9. #include "protos/tokenizer.h"
  10.  
  11. extern char *PyOS_Readline Py_PROTO((char *));
  12. /* Return malloc'ed string including trailing \n;
  13.    empty malloc'ed string for EOF;
  14.    NULL if interrupted */
  15.  
  16. /* Don't ever change this -- it would break the portability of Python code */
  17. #define TABSIZE 8
  18.  
  19. /* Convert a possibly signed character to a nonnegative int */
  20. /* XXX This assumes characters are 8 bits wide */
  21. #ifdef __CHAR_UNSIGNED__
  22. #define Py_CHARMASK(c)        (c)
  23. #else
  24. #define Py_CHARMASK(c)        ((c) & 0xff)
  25. #endif
  26.  
  27. /* Forward */
  28. static struct tok_state *tok_new Py_PROTO((void));
  29. static int tok_nextc Py_PROTO((struct tok_state *tok));
  30. static void tok_backup Py_PROTO((struct tok_state *tok, int c));
  31.  
  32. /* Token names */
  33.  
  34. char *_PyParser_TokenNames[] = {
  35.     "ENDMARKER",
  36.     "NAME",
  37.     "NUMBER",
  38.     "STRING",
  39.     "NEWLINE",
  40.     "INDENT",
  41.     "DEDENT",
  42.     "LPAR",
  43.     "RPAR",
  44.     "LSQB",
  45.     "RSQB",
  46.     "COLON",
  47.     "COMMA",
  48.     "SEMI",
  49.     "PLUS",
  50.     "MINUS",
  51.     "STAR",
  52.     "SLASH",
  53.     "VBAR",
  54.     "AMPER",
  55.     "LESS",
  56.     "GREATER",
  57.     "EQUAL",
  58.     "DOT",
  59.     "PERCENT",
  60.     "BACKQUOTE",
  61.     "LBRACE",
  62.     "RBRACE",
  63.     "EQEQUAL",
  64.     "NOTEQUAL",
  65.     "LESSEQUAL",
  66.     "GREATEREQUAL",
  67.     "TILDE",
  68.     "CIRCUMFLEX",
  69.     "LEFTSHIFT",
  70.     "RIGHTSHIFT",
  71.     "DOUBLESTAR",
  72.     /* This table must match the #defines in token.h! */
  73.     "OP",
  74.     "<ERRORTOKEN>",
  75.     "<N_TOKENS>"
  76. };
  77.  
  78.  
  79. /* Create and initialize a new tok_state structure */
  80.  
  81. static struct tok_state *
  82. tok_new()
  83. {
  84.     struct tok_state *tok = PyMem_NEW(struct tok_state, 1);
  85.     if (tok == NULL)
  86.         return NULL;
  87.     tok->buf = tok->cur = tok->end = tok->inp = tok->start = NULL;
  88.     tok->done = E_OK;
  89.     tok->fp = NULL;
  90.     tok->tabsize = TABSIZE;
  91.     tok->indent = 0;
  92.     tok->indstack[0] = 0;
  93.     tok->atbol = 1;
  94.     tok->pendin = 0;
  95.     tok->prompt = tok->nextprompt = NULL;
  96.     tok->lineno = 0;
  97.     tok->level = 0;
  98.     tok->filename = NULL;
  99.     tok->altwarning = 0;
  100.     tok->alterror = 0;
  101.     tok->alttabsize = 1;
  102.     tok->altindstack[0] = 0;
  103.     return tok;
  104. }
  105.  
  106.  
  107. /* Set up tokenizer for string */
  108.  
  109. struct tok_state *
  110. PyTokenizer_FromString(str)
  111.     char *str;
  112. {
  113.     struct tok_state *tok = tok_new();
  114.     if (tok == NULL)
  115.         return NULL;
  116.     tok->buf = tok->cur = tok->end = tok->inp = str;
  117.     return tok;
  118. }
  119.  
  120.  
  121. /* Set up tokenizer for file */
  122.  
  123. struct tok_state *
  124. PyTokenizer_FromFile(fp, ps1, ps2)
  125.     FILE *fp;
  126.     char *ps1, *ps2;
  127. {
  128.     struct tok_state *tok = tok_new();
  129.     if (tok == NULL)
  130.         return NULL;
  131.     if ((tok->buf = PyMem_NEW(char, BUFSIZ)) == NULL) {
  132.         PyMem_DEL(tok);
  133.         return NULL;
  134.     }
  135.     tok->cur = tok->inp = tok->buf;
  136.     tok->end = tok->buf + BUFSIZ;
  137.     tok->fp = fp;
  138.     tok->prompt = ps1;
  139.     tok->nextprompt = ps2;
  140.     return tok;
  141. }
  142.  
  143.  
  144. /* Free a tok_state structure */
  145.  
  146. void
  147. PyTokenizer_Free(tok)
  148.     struct tok_state *tok;
  149. {
  150.     if (tok->fp != NULL && tok->buf != NULL)
  151.         PyMem_DEL(tok->buf);
  152.     PyMem_DEL(tok);
  153. }
  154.  
  155.  
  156. /* Get next char, updating state; error code goes into tok->done */
  157.  
  158. static int
  159. tok_nextc(tok)
  160.     register struct tok_state *tok;
  161. {
  162.     for (;;) {
  163.         if (tok->cur != tok->inp) {
  164.             return Py_CHARMASK(*tok->cur++); /* Fast path */
  165.         }
  166.         if (tok->done != E_OK)
  167.             return EOF;
  168.         if (tok->fp == NULL) {
  169.             char *end = strchr(tok->inp, '\n');
  170.             if (end != NULL)
  171.                 end++;
  172.             else {
  173.                 end = strchr(tok->inp, '\0');
  174.                 if (end == tok->inp) {
  175.                     tok->done = E_EOF;
  176.                     return EOF;
  177.                 }
  178.             }
  179.             if (tok->start == NULL)
  180.                 tok->buf = tok->cur;
  181.             tok->lineno++;
  182.             tok->inp = end;
  183.             return Py_CHARMASK(*tok->cur++);
  184.         }
  185.         if (tok->prompt != NULL) {
  186.             char *new = PyOS_Readline(tok->prompt);
  187.             if (tok->nextprompt != NULL)
  188.                 tok->prompt = tok->nextprompt;
  189.             if (new == NULL)
  190.                 tok->done = E_INTR;
  191.             else if (*new == '\0') {
  192.                 PyMem_FREE(new);
  193.                 tok->done = E_EOF;
  194.             }
  195.             else if (tok->start != NULL) {
  196.                 int start = tok->start - tok->buf;
  197.                 int oldlen = tok->cur - tok->buf;
  198.                 int newlen = oldlen + strlen(new);
  199.                 char *buf = tok->buf;
  200.                 PyMem_RESIZE(buf, char, newlen+1);
  201.                 tok->lineno++;
  202.                 if (buf == NULL) {
  203.                     PyMem_DEL(tok->buf);
  204.                     tok->buf = NULL;
  205.                     PyMem_FREE(new);
  206.                     tok->done = E_NOMEM;
  207.                     return EOF;
  208.                 }
  209.                 tok->buf = buf;
  210.                 tok->cur = tok->buf + oldlen;
  211.                 strcpy(tok->buf + oldlen, new);
  212.                 PyMem_FREE(new);
  213.                 tok->inp = tok->buf + newlen;
  214.                 tok->end = tok->inp + 1;
  215.                 tok->start = tok->buf + start;
  216.             }
  217.             else {
  218.                 tok->lineno++;
  219.                 if (tok->buf != NULL)
  220.                     PyMem_DEL(tok->buf);
  221.                 tok->buf = new;
  222.                 tok->cur = tok->buf;
  223.                 tok->inp = strchr(tok->buf, '\0');
  224.                 tok->end = tok->inp + 1;
  225.             }
  226.         }
  227.         else {
  228.             int done = 0;
  229.             int cur = 0;
  230.             char *pt;
  231.             if (tok->start == NULL) {
  232.                 if (tok->buf == NULL) {
  233.                     tok->buf = PyMem_NEW(char, BUFSIZ);
  234.                     if (tok->buf == NULL) {
  235.                         tok->done = E_NOMEM;
  236.                         return EOF;
  237.                     }
  238.                     tok->end = tok->buf + BUFSIZ;
  239.                 }
  240.                 if (fgets(tok->buf, (int)(tok->end - tok->buf),
  241.                       tok->fp) == NULL) {
  242.                     tok->done = E_EOF;
  243.                     done = 1;
  244.                 }
  245.                 else {
  246.                     tok->done = E_OK;
  247.                     tok->inp = strchr(tok->buf, '\0');
  248.                     done = tok->inp[-1] == '\n';
  249.                 }
  250.             }
  251.             else {
  252.                 cur = tok->cur - tok->buf;
  253.                 if (feof(tok->fp)) {
  254.                     tok->done = E_EOF;
  255.                     done = 1;
  256.                 }
  257.                 else
  258.                     tok->done = E_OK;
  259.             }
  260.             tok->lineno++;
  261.             /* Read until '\n' or EOF */
  262.             while (!done) {
  263.                 int curstart = tok->start == NULL ? -1 :
  264.                            tok->start - tok->buf;
  265.                 int curvalid = tok->inp - tok->buf;
  266.                 int newsize = curvalid + BUFSIZ;
  267.                 char *newbuf = tok->buf;
  268.                 PyMem_RESIZE(newbuf, char, newsize);
  269.                 if (newbuf == NULL) {
  270.                     tok->done = E_NOMEM;
  271.                     tok->cur = tok->inp;
  272.                     return EOF;
  273.                 }
  274.                 tok->buf = newbuf;
  275.                 tok->inp = tok->buf + curvalid;
  276.                 tok->end = tok->buf + newsize;
  277.                 tok->start = curstart < 0 ? NULL :
  278.                          tok->buf + curstart;
  279.                 if (fgets(tok->inp,
  280.                            (int)(tok->end - tok->inp),
  281.                            tok->fp) == NULL) {
  282.                     /* Last line does not end in \n,
  283.                        fake one */
  284.                     strcpy(tok->inp, "\n");
  285.                 }
  286.                 tok->inp = strchr(tok->inp, '\0');
  287.                 done = tok->inp[-1] == '\n';
  288.             }
  289.             tok->cur = tok->buf + cur;
  290. #ifndef macintosh
  291.             /* replace "\r\n" with "\n" */
  292.             /* For Mac we leave the \r, giving a syntax error */
  293.             pt = tok->inp - 2;
  294.             if (pt >= tok->buf && *pt == '\r') {
  295.                 *pt++ = '\n';
  296.                 *pt = '\0';
  297.                 tok->inp = pt;
  298.             }
  299. #endif
  300.         }
  301.         if (tok->done != E_OK) {
  302.             if (tok->prompt != NULL)
  303.                 PySys_WriteStderr("\n");
  304.             tok->cur = tok->inp;
  305.             return EOF;
  306.         }
  307.     }
  308.     /*NOTREACHED*/
  309. }
  310.  
  311.  
  312. /* Back-up one character */
  313.  
  314. static void
  315. tok_backup(tok, c)
  316.     register struct tok_state *tok;
  317.     register int c;
  318. {
  319.     if (c != EOF) {
  320.         if (--tok->cur < tok->buf)
  321.             Py_FatalError("tok_backup: begin of buffer");
  322.         if (*tok->cur != c)
  323.             *tok->cur = c;
  324.     }
  325. }
  326.  
  327.  
  328. /* Return the token corresponding to a single character */
  329.  
  330. int
  331. PyToken_OneChar(c)
  332.     int c;
  333. {
  334.     switch (c) {
  335.     case '(':    return LPAR;
  336.     case ')':    return RPAR;
  337.     case '[':    return LSQB;
  338.     case ']':    return RSQB;
  339.     case ':':    return COLON;
  340.     case ',':    return COMMA;
  341.     case ';':    return SEMI;
  342.     case '+':    return PLUS;
  343.     case '-':    return MINUS;
  344.     case '*':    return STAR;
  345.     case '/':    return SLASH;
  346.     case '|':    return VBAR;
  347.     case '&':    return AMPER;
  348.     case '<':    return LESS;
  349.     case '>':    return GREATER;
  350.     case '=':    return EQUAL;
  351.     case '.':    return DOT;
  352.     case '%':    return PERCENT;
  353.     case '`':    return BACKQUOTE;
  354.     case '{':    return LBRACE;
  355.     case '}':    return RBRACE;
  356.     case '^':    return CIRCUMFLEX;
  357.     case '~':    return TILDE;
  358.     default:    return OP;
  359.     }
  360. }
  361.  
  362.  
  363. int
  364. PyToken_TwoChars(c1, c2)
  365.     int c1, c2;
  366. {
  367.     switch (c1) {
  368.     case '=':
  369.         switch (c2) {
  370.         case '=':    return EQEQUAL;
  371.         }
  372.         break;
  373.     case '!':
  374.         switch (c2) {
  375.         case '=':    return NOTEQUAL;
  376.         }
  377.         break;
  378.     case '<':
  379.         switch (c2) {
  380.         case '>':    return NOTEQUAL;
  381.         case '=':    return LESSEQUAL;
  382.         case '<':    return LEFTSHIFT;
  383.         }
  384.         break;
  385.     case '>':
  386.         switch (c2) {
  387.         case '=':    return GREATEREQUAL;
  388.         case '>':    return RIGHTSHIFT;
  389.         }
  390.         break;
  391.     case '*':
  392.         switch (c2) {
  393.         case '*':    return DOUBLESTAR;
  394.         }
  395.         break;
  396.     }
  397.     return OP;
  398. }
  399.  
  400.  
  401. static int
  402. indenterror(tok)
  403.     struct tok_state *tok;
  404. {
  405.     if (tok->alterror) {
  406.         tok->done = E_INDENT;
  407.         tok->cur = tok->inp;
  408.         return 1;
  409.     }
  410.     if (tok->altwarning) {
  411.         PySys_WriteStderr("%s: inconsistent tab/space usage\n",
  412.             tok->filename);
  413.         tok->altwarning = 0;
  414.     }
  415.     return 0;
  416. }
  417.  
  418.  
  419. /* Get next token, after space stripping etc. */
  420.  
  421. int
  422. PyTokenizer_Get(tok, p_start, p_end)
  423.     register struct tok_state *tok; /* In/out: tokenizer state */
  424.     char **p_start, **p_end; /* Out: point to start/end of token */
  425. {
  426.     register int c;
  427.     int blankline;
  428.  
  429.     *p_start = *p_end = NULL;
  430.   nextline:
  431.     tok->start = NULL;
  432.     blankline = 0;
  433.  
  434.     /* Get indentation level */
  435.     if (tok->atbol) {
  436.         register int col = 0;
  437.         register int altcol = 0;
  438.         tok->atbol = 0;
  439.         for (;;) {
  440.             c = tok_nextc(tok);
  441.             if (c == ' ')
  442.                 col++, altcol++;
  443.             else if (c == '\t') {
  444.                 col = (col/tok->tabsize + 1) * tok->tabsize;
  445.                 altcol = (altcol/tok->alttabsize + 1)
  446.                     * tok->alttabsize;
  447.             }
  448.             else if (c == '\014') /* Control-L (formfeed) */
  449.                 col = altcol = 0; /* For Emacs users */
  450.             else
  451.                 break;
  452.         }
  453.         tok_backup(tok, c);
  454.         if (c == '#' || c == '\n') {
  455.             /* Lines with only whitespace and/or comments
  456.                shouldn't affect the indentation and are
  457.                not passed to the parser as NEWLINE tokens,
  458.                except *totally* empty lines in interactive
  459.                mode, which signal the end of a command group. */
  460.             if (col == 0 && c == '\n' && tok->prompt != NULL)
  461.                 blankline = 0; /* Let it through */
  462.             else
  463.                 blankline = 1; /* Ignore completely */
  464.             /* We can't jump back right here since we still
  465.                may need to skip to the end of a comment */
  466.         }
  467.         if (!blankline && tok->level == 0) {
  468.             if (col == tok->indstack[tok->indent]) {
  469.                 /* No change */
  470.                 if (altcol != tok->altindstack[tok->indent]) {
  471.                     if (indenterror(tok))
  472.                         return ERRORTOKEN;
  473.                 }
  474.             }
  475.             else if (col > tok->indstack[tok->indent]) {
  476.                 /* Indent -- always one */
  477.                 if (tok->indent+1 >= MAXINDENT) {
  478.                     PySys_WriteStderr(
  479.                         "excessive indent\n");
  480.                     tok->done = E_TOKEN;
  481.                     tok->cur = tok->inp;
  482.                     return ERRORTOKEN;
  483.                 }
  484.                 if (altcol <= tok->altindstack[tok->indent]) {
  485.                     if (indenterror(tok))
  486.                         return ERRORTOKEN;
  487.                 }
  488.                 tok->pendin++;
  489.                 tok->indstack[++tok->indent] = col;
  490.                 tok->altindstack[tok->indent] = altcol;
  491.             }
  492.             else /* col < tok->indstack[tok->indent] */ {
  493.                 /* Dedent -- any number, must be consistent */
  494.                 while (tok->indent > 0 &&
  495.                     col < tok->indstack[tok->indent]) {
  496.                     tok->pendin--;
  497.                     tok->indent--;
  498.                 }
  499.                 if (col != tok->indstack[tok->indent]) {
  500.                     PySys_WriteStderr(
  501.                         "inconsistent dedent\n");
  502.                     tok->done = E_TOKEN;
  503.                     tok->cur = tok->inp;
  504.                     return ERRORTOKEN;
  505.                 }
  506.                 if (altcol != tok->altindstack[tok->indent]) {
  507.                     if (indenterror(tok))
  508.                         return ERRORTOKEN;
  509.                 }
  510.             }
  511.         }
  512.     }
  513.     
  514.     tok->start = tok->cur;
  515.     
  516.     /* Return pending indents/dedents */
  517.     if (tok->pendin != 0) {
  518.         if (tok->pendin < 0) {
  519.             tok->pendin++;
  520.             return DEDENT;
  521.         }
  522.         else {
  523.             tok->pendin--;
  524.             return INDENT;
  525.         }
  526.     }
  527.     
  528.  again:
  529.     tok->start = NULL;
  530.     /* Skip spaces */
  531.     do {
  532.         c = tok_nextc(tok);
  533.     } while (c == ' ' || c == '\t' || c == '\014');
  534.     
  535.     /* Set start of current token */
  536.     tok->start = tok->cur - 1;
  537.     
  538.     /* Skip comment, while looking for tab-setting magic */
  539.     if (c == '#') {
  540.         static char *tabforms[] = {
  541.             "tab-width:",        /* Emacs */
  542.             ":tabstop=",        /* vim, full form */
  543.             ":ts=",            /* vim, abbreviated form */
  544.             "set tabsize=",        /* will vi never die? */
  545.         /* more templates can be added here to support other editors */
  546.         };
  547.         char cbuf[80];
  548.         char *tp, **cp;
  549.         tp = cbuf;
  550.         do {
  551.             *tp++ = c = tok_nextc(tok);
  552.         } while (c != EOF && c != '\n' &&
  553.              tp - cbuf + 1 < sizeof(cbuf));
  554.         *tp = '\0';
  555.         for (cp = tabforms; 
  556.              cp < tabforms + sizeof(tabforms)/sizeof(tabforms[0]);
  557.              cp++) {
  558.             if ((tp = strstr(cbuf, *cp))) {
  559.                 int newsize = atoi(tp + strlen(*cp));
  560.  
  561.                 if (newsize >= 1 && newsize <= 40) {
  562.                     tok->tabsize = newsize;
  563.                     if (Py_VerboseFlag)
  564.                         PySys_WriteStderr(
  565.                         "Tab size set to %d\n",
  566.                         newsize);
  567.                 }
  568.             }
  569.         }
  570.         while (c != EOF && c != '\n')
  571.             c = tok_nextc(tok);
  572.     }
  573.     
  574.     /* Check for EOF and errors now */
  575.     if (c == EOF) {
  576.         return tok->done == E_EOF ? ENDMARKER : ERRORTOKEN;
  577.     }
  578.     
  579.     /* Identifier (most frequent token!) */
  580.     if (isalpha(c) || c == '_') {
  581.         /* Process r"", u"" and ur"" */
  582.         switch (c) {
  583.         case 'r':
  584.         case 'R':
  585.             c = tok_nextc(tok);
  586.             if (c == '"' || c == '\'')
  587.                 goto letter_quote;
  588.             break;
  589.         case 'u':
  590.         case 'U':
  591.             c = tok_nextc(tok);
  592.             if (c == 'r' || c == 'R')
  593.                 c = tok_nextc(tok);
  594.             if (c == '"' || c == '\'')
  595.                 goto letter_quote;
  596.             break;
  597.         }
  598.         while (isalnum(c) || c == '_') {
  599.             c = tok_nextc(tok);
  600.         }
  601.         tok_backup(tok, c);
  602.         *p_start = tok->start;
  603.         *p_end = tok->cur;
  604.         return NAME;
  605.     }
  606.     
  607.     /* Newline */
  608.     if (c == '\n') {
  609.         tok->atbol = 1;
  610.         if (blankline || tok->level > 0)
  611.             goto nextline;
  612.         *p_start = tok->start;
  613.         *p_end = tok->cur - 1; /* Leave '\n' out of the string */
  614.         return NEWLINE;
  615.     }
  616.     
  617. #ifdef macintosh
  618.     if (c == '\r') {
  619.         PySys_WriteStderr(
  620.           "File contains \\r characters (incorrect line endings?)\n");
  621.         tok->done = E_TOKEN;
  622.         tok->cur = tok->inp;
  623.         return ERRORTOKEN;
  624.     }
  625. #endif    
  626.     /* Period or number starting with period? */
  627.     if (c == '.') {
  628.         c = tok_nextc(tok);
  629.         if (isdigit(c)) {
  630.             goto fraction;
  631.         }
  632.         else {
  633.             tok_backup(tok, c);
  634.             *p_start = tok->start;
  635.             *p_end = tok->cur;
  636.             return DOT;
  637.         }
  638.     }
  639.  
  640.     /* Number */
  641.     if (isdigit(c)) {
  642.         if (c == '0') {
  643.             /* Hex or octal */
  644.             c = tok_nextc(tok);
  645.             if (c == '.')
  646.                 goto fraction;
  647. #ifndef WITHOUT_COMPLEX
  648.             if (c == 'j' || c == 'J')
  649.                 goto imaginary;
  650. #endif
  651.             if (c == 'x' || c == 'X') {
  652.                 /* Hex */
  653.                 do {
  654.                     c = tok_nextc(tok);
  655.                 } while (isxdigit(c));
  656.             }
  657.             else {
  658.                 /* XXX This is broken!  E.g.,
  659.                    09.9 should be accepted as float! */
  660.                 /* Octal; c is first char of it */
  661.                 /* There's no 'isoctdigit' macro, sigh */
  662.                 while ('0' <= c && c < '8') {
  663.                     c = tok_nextc(tok);
  664.                 }
  665.             }
  666.             if (c == 'l' || c == 'L')
  667.                 c = tok_nextc(tok);
  668.         }
  669.         else {
  670.             /* Decimal */
  671.             do {
  672.                 c = tok_nextc(tok);
  673.             } while (isdigit(c));
  674.             if (c == 'l' || c == 'L')
  675.                 c = tok_nextc(tok);
  676.             else {
  677.                 /* Accept floating point numbers.
  678.                    XXX This accepts incomplete things like
  679.                    XXX 12e or 1e+; worry run-time */
  680.                 if (c == '.') {
  681.         fraction:
  682.                     /* Fraction */
  683.                     do {
  684.                         c = tok_nextc(tok);
  685.                     } while (isdigit(c));
  686.                 }
  687.                 if (c == 'e' || c == 'E') {
  688.                     /* Exponent part */
  689.                     c = tok_nextc(tok);
  690.                     if (c == '+' || c == '-')
  691.                         c = tok_nextc(tok);
  692.                     while (isdigit(c)) {
  693.                         c = tok_nextc(tok);
  694.                     }
  695.                 }
  696. #ifndef WITHOUT_COMPLEX
  697.                 if (c == 'j' || c == 'J')
  698.                     /* Imaginary part */
  699.         imaginary:
  700.                     c = tok_nextc(tok);
  701. #endif
  702.             }
  703.         }
  704.         tok_backup(tok, c);
  705.         *p_start = tok->start;
  706.         *p_end = tok->cur;
  707.         return NUMBER;
  708.     }
  709.  
  710.   letter_quote:
  711.     /* String */
  712.     if (c == '\'' || c == '"') {
  713.         int quote2 = tok->cur - tok->start + 1;
  714.         int quote = c;
  715.         int triple = 0;
  716.         int tripcount = 0;
  717.         for (;;) {
  718.             c = tok_nextc(tok);
  719.             if (c == '\n') {
  720.                 if (!triple) {
  721.                     tok->done = E_TOKEN;
  722.                     tok_backup(tok, c);
  723.                     return ERRORTOKEN;
  724.                 }
  725.                 tripcount = 0;
  726.             }
  727.             else if (c == EOF) {
  728.                 tok->done = E_TOKEN;
  729.                 tok->cur = tok->inp;
  730.                 return ERRORTOKEN;
  731.             }
  732.             else if (c == quote) {
  733.                 tripcount++;
  734.                 if (tok->cur - tok->start == quote2) {
  735.                     c = tok_nextc(tok);
  736.                     if (c == quote) {
  737.                         triple = 1;
  738.                         tripcount = 0;
  739.                         continue;
  740.                     }
  741.                     tok_backup(tok, c);
  742.                 }
  743.                 if (!triple || tripcount == 3)
  744.                     break;
  745.             }
  746.             else if (c == '\\') {
  747.                 tripcount = 0;
  748.                 c = tok_nextc(tok);
  749.                 if (c == EOF) {
  750.                     tok->done = E_TOKEN;
  751.                     tok->cur = tok->inp;
  752.                     return ERRORTOKEN;
  753.                 }
  754.             }
  755.             else
  756.                 tripcount = 0;
  757.         }
  758.         *p_start = tok->start;
  759.         *p_end = tok->cur;
  760.         return STRING;
  761.     }
  762.     
  763.     /* Line continuation */
  764.     if (c == '\\') {
  765.         c = tok_nextc(tok);
  766.         if (c != '\n') {
  767.             tok->done = E_TOKEN;
  768.             tok->cur = tok->inp;
  769.             return ERRORTOKEN;
  770.         }
  771.         goto again; /* Read next line */
  772.     }
  773.     
  774.     /* Check for two-character token */
  775.     {
  776.         int c2 = tok_nextc(tok);
  777.         int token = PyToken_TwoChars(c, c2);
  778.         if (token != OP) {
  779.             *p_start = tok->start;
  780.             *p_end = tok->cur;
  781.             return token;
  782.         }
  783.         tok_backup(tok, c2);
  784.     }
  785.     
  786.     /* Keep track of parentheses nesting level */
  787.     switch (c) {
  788.     case '(':
  789.     case '[':
  790.     case '{':
  791.         tok->level++;
  792.         break;
  793.     case ')':
  794.     case ']':
  795.     case '}':
  796.         tok->level--;
  797.         break;
  798.     }
  799.     
  800.     /* Punctuation character */
  801.     *p_start = tok->start;
  802.     *p_end = tok->cur;
  803.     return PyToken_OneChar(c);
  804. }
  805.  
  806.  
  807. #ifdef Py_DEBUG
  808.  
  809. void
  810. tok_dump(type, start, end)
  811.     int type;
  812.     char *start, *end;
  813. {
  814.     printf("%s", _PyParser_TokenNames[type]);
  815.     if (type == NAME || type == NUMBER || type == STRING || type == OP)
  816.         printf("(%.*s)", (int)(end - start), start);
  817. }
  818.  
  819. #endif
  820.